﻿using OPCAutomation;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OPCDADemo
{
    public partial class Form1 : Form
    {
        private OPCServer opcServer;
        private OPCGroup group;
        private OPCItem item;

        public Form1()
        {
            InitializeComponent();
            InitOpc();
        }

        private void InitOpc()
        {
            // 创建OPC服务器对象
            opcServer = new OPCServer();
            // 参数1：连接到哪个服务器的唯一ID
            opcServer.Connect("Kepware.KEPServerEX.V6");

            // 遍历标签
            //OPCBrowser browser = opcServer.CreateBrowser();
            //browser.ShowBranches();  // 显示分支
            //browser.ShowLeafs(true); // 显示叶子节点

            //// 遍历节点
            //foreach (var item in browser)
            //{
            //    label1.Text += item.ToString() + "\n";
            //}

            // 数据读写
            // 所有要读的数据都放在一个数据组里面
            OPCGroups groups = opcServer.OPCGroups;
            group = groups.Add("Tuling");
            OPCItems items = group.OPCItems;
            // 参数1:读取项
            // 参数2:10自己设置的，代表读的一个句柄
            item = items.AddItem("ModbusRTU.ModbusRTUOne.温度数据", 10);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                // 参数1：OPCDataSource枚举有2个值:OPCCache从缓存读取，OPCDevice从设备读取
                // 参数2：读取几项数据
                // 参数3：OPC数组从1开始的，所以要有一个0的占位符,item.ServerHandle:服务的句柄
                var serverHandles = new int[2] { 0, item.ServerHandle };
                var serverHandleArray = (Array)serverHandles;
                var values = new object[2];
                var valuesArray = (Array)values;
                var errors = new string[2];
                var errorsArray = (Array)errors;

                // 读取数据
                #region 同步读取
                //group.SyncRead((short)OPCAutomation.OPCDataSource.OPCDevice,
                //    1,
                //    ref serverHandleArray,
                //    out valuesArray,
                //    out errorsArray,
                //    out var qualities,
                //    out var timeStamps
                //);

                //label1.Text = string.Empty;

                //// 显示读取的数据
                //for (int i = 1; i <= valuesArray.Length; i++)
                //{
                //    label1.Text += valuesArray.GetValue(i).ToString() + "\n";
                //}
                #endregion

                #region 异步读取
                //group.IsSubscribed = true; // 异步读取实际走的是订阅流
                //group.AsyncRead(1, ref serverHandleArray, out errorsArray, 12, out var cancelId);
                //// 调用回调函数
                //group.AsyncReadComplete += Group_AsyncReadComplete;
                #endregion

                #region 订阅模式读取(只在数据变化的时候触发)
                // 如果值一直变化，就一直触发DataChange事件
                //group.IsSubscribed = true;
                //group.DataChange += Group_DataChange;
                #endregion

                #region 同步写入
                //Random random = new Random();
                //var randomValue = random.Next(1, 10);
                //var valueWrites = new object[2] { 0, randomValue };
                //var valluesWritesArray = (Array)valueWrites;
                //group.SyncWrite(1, ref serverHandleArray, ref valluesWritesArray, out errorsArray);
                #endregion

                #region 异步写入
                var random = new Random();
                var randomValue = random.Next(1, 10);
                var valueWrites = new object[2] { 0, randomValue };
                var valuesWritesArray = (Array)valueWrites;
                group.IsSubscribed = true;
                group.AsyncWrite(1, ref serverHandleArray, ref valuesWritesArray, out errorsArray,
                    10, out var cancelId);
                group.AsyncWriteComplete += Group_AsyncWriteComplete;
                #endregion

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void Group_AsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors)
        {
            // 如果你想要获取 error 详细的错误信息
            //string str=opcServer.GetErrorString(1);
        }

        private void Group_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
        {
            try
            {
                label1.Text = string.Empty;

                // 显示读取的数据
                for (int i = 1; i <= ItemValues.Length; i++)
                {
                    label1.Text += ItemValues.GetValue(i).ToString() + "\n";
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }

        }

        private void Group_AsyncReadComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps, ref Array Errors)
        {
            label1.Text = string.Empty;

            // 显示读取的数据
            for (int i = 1; i <= ItemValues.Length; i++)
            {
                label1.Text += ItemValues.GetValue(i).ToString() + "\n";
            }
        }
    }
}
